package com.diankangwo.util;

import cn.beecloud.BCEumeration.PAY_CHANNEL;
import cn.beecloud.BCEumeration.QR_PAY_MODE;
import cn.beecloud.BCPay;
import cn.beecloud.BeeCloud;
import cn.beecloud.bean.*;
import org.apache.log4j.Logger;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

public class BeecloudPayUtil {

    ReentrantLock lock = new ReentrantLock();

    Logger log = Logger.getLogger(this.getClass());

    // returnUrl(商户根据自身系统指定)
    private String aliWebReturnUrl;
    private String aliWapReturnUrl;
    private String unWebReturnUrl;
    private String unWapReturnUrl;

    public BeecloudPayUtil() {
        Properties prop = LoadPropertyUtil.loadProperty("beecloudPay.properties");
        // 获取项目 APP ID 和 APP Secret
        String appID = prop.get("appId").toString();
        String appSecret = prop.get("appSecret").toString();
        String MasterSecret = prop.get("MasterSecret").toString();
        String TestSecret = prop.get("TestSecret").toString();
        // 支付回调地址
        aliWebReturnUrl = prop.getProperty("aliWebReturnUrl");
        aliWapReturnUrl = prop.getProperty("aliWapReturnUrl");
        unWebReturnUrl = prop.getProperty("unWebReturnUrl");
        unWapReturnUrl = prop.getProperty("unWapReturnUrl");
        // 注册支付信息
        BeeCloud.registerApp(appID, TestSecret, appSecret, MasterSecret);
    }

    public static void registerApp() {
        Properties prop = LoadPropertyUtil.loadProperty("beecloudPay.properties");
        String appID = prop.get("appId").toString();
        String appSecret = prop.get("appSecret").toString();
        String MasterSecret = prop.get("MasterSecret").toString();
        String TestSecret = prop.get("TestSecret").toString();
        // 注册支付信息
        BeeCloud.registerApp(appID, TestSecret, appSecret, MasterSecret);
    }

    /**
     * 通用支付方法
     *
     * @param param 支付参数
     * @return BCPayResult | null [调用者自行处理结果]
     */
    public BCOrder commonPay(BCOrder param) {

        BCOrder bcPayResult = new BCOrder();
        try {
            lock.lock();
            bcPayResult = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return bcPayResult;
    }

    /**
     * 微信扫码支付
     *
     * @param totalFee 订单金额,单位为分
     * @param billNo   商户订单号,8到20位字符,唯一
     * @param title    订单标题
     * @return BCPayResult | null [调用者自行处理支付结果]
     */
    public BCOrder wechatQrsPay(Integer totalFee, String billNo, String title) {
        BCOrder param = new BCOrder(PAY_CHANNEL.WX_NATIVE, totalFee, billNo, title);
        param.setBillTimeout(600);
        param.setOptional(null);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 微信APP支付
     *
     * @param totalFee 订单金额,单位为分
     * @param billNo   商户订单号,8到20位字符,唯一
     * @param title    订单标题
     * @return BCPayResult | null [调用者自行处理支付结果]
     */
    public BCOrder weAppPay(Integer totalFee, String billNo, String title) {
        BCOrder param = new BCOrder(PAY_CHANNEL.WX_APP, totalFee, billNo, title);
        param.setBillTimeout(600);
        param.setOptional(null);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }


    /**
     * 阿里网页支付
     *
     * @param totalFee 订单金额,单位为分
     * @param billNo   商户订单号,8到20位字符,唯一
     * @param title    订单标题
     * @param optional 附加数据<选填>
     * @return BCPayResult | null [调用者自行处理支付结果]
     */
    public BCOrder aliPay(Integer totalFee, String billNo, String title, Map<String, Object> optional) {
        BCOrder param = new BCOrder(PAY_CHANNEL.ALI_WEB, totalFee, billNo, title);
        param.setReturnUrl(aliWebReturnUrl);
        param.setBillTimeout(600);
        param.setOptional(optional);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 阿里网页支付
     *
     * @param totalFee 订单金额,单位为分
     * @param billNo   商户订单号,8到20位字符,唯一
     * @param title    订单标题
     * @param optional 附加数据<选填>
     * @return BCPayResult | null [调用者自行处理支付结果]
     */
    public BCOrder aliPayApp(Integer totalFee, String billNo, String title, Map<String, Object> optional) {
        BCOrder param = new BCOrder(PAY_CHANNEL.ALI_APP, totalFee, billNo, title);
        param.setReturnUrl(aliWebReturnUrl);
        param.setBillTimeout(600);
        param.setOptional(optional);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 阿里扫码支付
     *
     * @param totalFee 订单金额
     * @param billNo   商户订单号,8到20位字符,唯一
     * @param title    订单标题
     * @return BCPayResult | null [调用者自行处理支付结果]
     */
    public BCOrder aliQrPay(Integer totalFee, String billNo, String title) {
        BCOrder param = new BCOrder(PAY_CHANNEL.ALI_QRCODE, totalFee, billNo, title);
        param.setReturnUrl(aliWebReturnUrl);
        param.setQrPayMode(QR_PAY_MODE.MODE_FRONT);
        param.setBillTimeout(600);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 阿里移动网页支付
     *
     * @param totalFee 订单金额,单位为分
     * @param billNo   商户订单号,8到20位字符,唯一
     * @param title    订单标题
     * @return BCPayResult | null [调用者自行处理支付结果]
     */
    public BCOrder aliwapPay(Integer totalFee, String billNo, String title) {
        BCOrder param = new BCOrder(PAY_CHANNEL.ALI_WAP, totalFee, billNo, title);
        param.setBillTimeout(600);
        param.setReturnUrl(aliWapReturnUrl);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 银联网页
     *
     * @param totalFee 订单总金额，只能为整数，单位为分，例如1，(必填)
     * @param billNo   商户订单号，8到20个字符内，数字和/或字母组合，确保在商户系统中唯一，例如(201506101035040000001),
     *                 (必填)
     * @param title    订单标题， 32个字节内，最长支持16个汉字，(必填)
     * @return 正确状态返回HTML，错误状态记录日志并返回null
     * @throws InterruptedException
     */
    public BCOrder unionWebPay(Integer totalFee, String billNo, String title) throws InterruptedException {
        BCOrder param = new BCOrder(PAY_CHANNEL.UN_WEB, totalFee, billNo, title);
        param.setReturnUrl(unWebReturnUrl);
        param.setBillTimeout(600);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 银联网页
     *
     * @param totalFee 订单总金额，只能为整数，单位为分，例如1，(必填)
     * @param billNo   商户订单号，8到20个字符内，数字和/或字母组合，确保在商户系统中唯一，例如(201506101035040000001),
     *                 (必填)
     * @param title    订单标题， 32个字节内，最长支持16个汉字，(必填)
     * @return 正确状态返回HTML，错误状态记录日志并返回null
     * @throws InterruptedException
     */
    public BCOrder unionWapPay(Integer totalFee, String billNo, String title) throws InterruptedException {
        BCOrder param = new BCOrder(PAY_CHANNEL.UN_WEB, totalFee, billNo, title);
        param.setReturnUrl(unWapReturnUrl);
        param.setBillTimeout(600);
        try {
            lock.lock();
            param = BCPay.startBCPay(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 查询所有支付订单
     *
     * @param channel 支付渠道
     * @return BCQueryResult | null [调用者自行处理查询结果]
     */
    public List<BCOrder> BCQuery(PAY_CHANNEL channel) {
        BCQueryParameter param = new BCQueryParameter();
        param.setChannel(channel);
        List<BCOrder> bcQueryResult = new ArrayList<BCOrder>();
        try {
            lock.lock();
            bcQueryResult = BCPay.startQueryBill(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return bcQueryResult;
    }

    /**
     * 查询所有退款订单
     *
     * @param channel 退款渠道
     * @return BCQueryResult | null [调用者自行处理查询结果]
     */
    public List<BCRefund> BCRefundQuery(PAY_CHANNEL channel) {
        BCRefundQueryParameter param = new BCRefundQueryParameter();
        param.setChannel(channel);
        List<BCRefund> bcList = new ArrayList<BCRefund>();
        try {
            lock.lock();
            bcList = BCPay.startQueryRefund(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return bcList;
    }

    /**
     * 查询支付订单(指定ID)
     *
     * @param id [object id]
     * @return BCQueryResult | null [调用者自行处理查询结果]
     */
    public BCOrder BCQueryById(String id) {
        BCOrder result = new BCOrder();
        try {
            lock.lock();
            result = BCPay.startQueryBillById(id);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 查询退款订单(指定ID)
     *
     * @param id [object id]
     * @return BCQueryResult | null [调用者自行处理查询结果]
     */
    public BCRefund BCQueryRefundById(String id) {
        BCRefund result = new BCRefund();
        try {
            lock.lock();
            result = BCPay.startQueryRefundById(id);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 退款状态查询
     *
     * @param channel  查询渠道
     * @param refundNo 商户订单号
     * @return BCQueryStatusResult | null [调用者自行处理查询结果]
     */
    public String BCqueryStatusResult(PAY_CHANNEL channel, String refundNo) {
        String result = "";
        try {
            lock.lock();
            result = BCPay.startRefundUpdate(channel, refundNo);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 退款
     *
     * @param billNo    商户订单号,32个字符内,唯一
     * @param refundNo  商户退款单号,当前退款日期8位+流水号3~24位,唯一
     * @param refundFee 退款金额
     * @param optional  附加数据
     * @return BCPayResult | null [调用者自行处理退款数据]
     */
    public BCRefund BCRefundParamter(String billNo, String refundNo, Integer refundFee,PAY_CHANNEL Channel, Map<String, Object> optional) {
        BCRefund param = new BCRefund(billNo, refundNo, refundFee, Channel);
        param.setOptional(optional);
        try {
            lock.lock();
            param = BCPay.startBCRefund(param);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return param;
    }

    /**
     * 批量打款(暂时只支持阿里)
     *
     * @param tp  批量打款参数类
     * @return url
     */
    public String batchPayment(TransfersParameter tp) {
        String bcPayResult = "";
        try {
            lock.lock();
            bcPayResult = BCPay.startTransfers(tp);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return bcPayResult;
    }

    /**
     * 单笔打款接口
     *
     * @param para
     * {@link TransferParameter} （必填）单笔打款参数
     * @return 如果channel类型是TRANSFER_CHANNEL.ALI_TRANSFER, 返回需要跳转支付的url, 否则返回空字符串
     * @throws BCException
     */
    public Map<String, Object> startBCTransfer(BCTransferParameter para) {
        Map<String, Object> result = new HashMap<>();
        try {
            lock.lock();
            result = BCPay.startBCTransfer(para);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return result;
    }
}
